/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef METHODE_UPANDDOWN_H
#define METHODE_UPANDDOWN_H

#include <QMetaType>
#include <QMultiHash>

#include "seuil/methode.h"

#include "rack.h"

namespace seuil {
namespace methode {

/*! Méthode <em>Up \& Down</em>.
    Cette méthode qualitative se découpe en trois phases distinctes :
    \li Phase <strong>Up</strong> : Tant que le patient répond \em non (absence de douleur),
    l'intensité de la stimulation est augmentée.
    \li Phase de <strong>Confirmation</strong> : Au premier \em oui, on entre dans cette phase.
    L'intensité est alors augmentée à nouveau. Si le patient répond \em oui l'expérience se poursuit.
    Autrement, elle est annulée.
    \li Phase <strong>Down</strong> : Tant que le patient répond \em oui, l'intensité est diminuée.
    Au premier \em non, l'expérience s'arrête.

    La moyenne des deux \em oui extrêmes donne le seuil.

    \attention Dans le cas où toutes les réponses sont négatives (absence de douleur),
    la valeur renvoyée est std::numeric_limits<qreal>::max(). De fait, si un Outil venait à avoir
    cette valeur, cela pourrait porter à confusion - mais ce cas est improbable.
*/
class UpAndDown : public Methode
{
Q_OBJECT
//! Phase courante.
Q_PROPERTY(Phase phase READ phase NOTIFY phaseChangee)

//! Rack utilisé.
Q_PROPERTY(Rack* rack READ rack WRITE setRack)

//! Les Phases.
Q_ENUMS(Phase)
public:
    //! Les différentes Phases.
    enum Phase { Up, Confirmation, Down };

    //! Constructeur.
    explicit UpAndDown(QObject *parent = 0);

    /*! Fournit le seuil calculé.
        Le seuil est déterminé selon l'algorithme suivant :
        \verbatim
        si il y a des ouis et des nons:
            si il y a au moins deux ouis:
                seuil = moyenne du premier et du dernier oui.
        sinon:
            si il n'y a que des nons:
                seuil = un maximum.
            sinon:
                seuil = 0
        \endverbatim
    */
    QVariant valeur() const;



    /*! Unité utilisée par la méthode.
        \return L'unité utilisée par la Méthode.
    */
    QString unite() const { return "Newton"; }

    /*! Phase courante.
        \return La phase actuelle de cette Méthode.
    */
    Phase phase() const { return phase_; }

    /*! Rack utilisé.
        \return Le Rack utilisé pour cette méthode.
    */
    Rack *rack() const { return rack_; }

public slots:
    /*! Change de Rack.
        \param rack Nouveau Rack.
    */
    void setRack(Rack *rack) { Q_CHECK_PTR(rack); rack_ = rack; }

    /*! Logique de transition.
        Contrôle la logique de transition entre les différentes phases, suivant la douleur perçue.
    */
    void douleur(const QVariant &douleur);

signals:
    /*! Changement de Phase.
        Emis lorsque la Phase courante a changé.
        \param phase La nouvelle phase.
    */
    void phaseChangee(int phase);

protected:
    /*! Changement de phase.
        \param[in] phase La nouvelle phase.
    */
    void setPhase(Phase phase) { phase_ = phase; emit phaseChangee(phase_); }

    //! Détermination <em>Up \& Down</em>.
    void determiner();

    Phase phase_; //!< Phase courante.
    Rack *rack_; //!< Rack utilisé.
    Rack::Iterateur rack_iter_; //!< Itérateur sur les filaments.
    QMultiHash<bool, qreal> douleurs_; //!< Liste des intensités associées à un état de douleur.

};

} // namespace methode
} // namespace seuil
#endif // METHODE_UPANDDOWN_H
